"""
SQL词法分析器 V2.0
完全符合实践要求：输出[种别码,词素值,行号,列号]格式
"""

import ply.lex as lex
import re

class Token:
    """Token类，包含种别码、词素值、行号、列号"""
    
    def __init__(self, type, value, line, column):
        self.type = type
        self.value = value
        self.line = line
        self.column = column
    
    def __repr__(self):
        return f"[{self.type}, {self.value}, {self.line}, {self.column}]"

class SQLLexerV2:
    """SQL词法分析器 V2.0"""
    
    def __init__(self):
        """初始化词法分析器"""
        self.lexer = lex.lex(module=self)
        self.tokens = self.tokens
        self.token_list = []
    
    # 定义token类型
    tokens = (
        # 关键字
        'SELECT', 'FROM', 'WHERE', 'INSERT', 'INTO', 'VALUES', 'DELETE',
        'CREATE', 'TABLE', 'DROP', 'INT', 'VARCHAR', 'FLOAT', 'BOOLEAN',
        'AND', 'OR', 'NOT', 'NULL', 'PRIMARY', 'KEY', 'UPDATE', 'SET',
        
        # 操作符
        'EQ', 'NE', 'LT', 'LE', 'GT', 'GE', 'PLUS', 'MINUS', 'TIMES', 'DIVIDE',
        'ASSIGN', 'COMMA', 'SEMICOLON', 'LPAREN', 'RPAREN', 'DOT',
        
        # 字面量
        'NUMBER', 'STRING', 'IDENTIFIER'
    )
    
    # 关键字映射
    keywords = {
        'select': 'SELECT',
        'from': 'FROM',
        'where': 'WHERE',
        'insert': 'INSERT',
        'into': 'INTO',
        'values': 'VALUES',
        'delete': 'DELETE',
        'create': 'CREATE',
        'table': 'TABLE',
        'drop': 'DROP',
        'int': 'INT',
        'varchar': 'VARCHAR',
        'float': 'FLOAT',
        'boolean': 'BOOLEAN',
        'and': 'AND',
        'or': 'OR',
        'not': 'NOT',
        'null': 'NULL',
        'primary': 'PRIMARY',
        'key': 'KEY',
        'update': 'UPDATE',
        'set': 'SET'
    }
    
    # 操作符定义
    t_EQ = r'='
    t_NE = r'!='
    t_LT = r'<'
    t_LE = r'<='
    t_GT = r'>'
    t_GE = r'>='
    t_PLUS = r'\+'
    t_MINUS = r'-'
    t_TIMES = r'\*'
    t_DIVIDE = r'/'
    t_ASSIGN = r':='
    t_COMMA = r','
    t_SEMICOLON = r';'
    t_LPAREN = r'\('
    t_RPAREN = r'\)'
    t_DOT = r'\.'
    
    # 数字字面量
    def t_NUMBER(self, t):
        r'\d+(\.\d+)?'
        if '.' in t.value:
            t.value = float(t.value)
        else:
            t.value = int(t.value)
        return t
    
    # 字符串字面量
    def t_STRING(self, t):
        r"'([^'\\]|\\.)*'|\"([^\"\\]|\\.)*\""
        t.value = t.value[1:-1]  # 去掉引号
        return t
    
    # 标识符
    def t_IDENTIFIER(self, t):
        r'[a-zA-Z_][a-zA-Z0-9_]*'
        t.type = self.keywords.get(t.value.lower(), 'IDENTIFIER')
        return t
    
    # 注释
    def t_COMMENT(self, t):
        r'--.*'
        pass  # 忽略注释
    
    # 空白字符
    t_ignore = ' \t'
    
    # 换行符处理
    def t_newline(self, t):
        r'\n+'
        t.lexer.lineno += len(t.value)
    
    # 错误处理
    def t_error(self, t):
        column = t.lexpos - self.lexer.lexdata.rfind('\n', 0, t.lexpos)
        print(f"词法错误: 非法字符 '{t.value[0]}' 在位置 ({t.lineno}, {column})")
        t.lexer.skip(1)
    
    def tokenize(self, text):
        """对输入文本进行词法分析，返回Token列表"""
        self.lexer.input(text)
        self.token_list = []
        
        while True:
            tok = self.lexer.token()
            if not tok:
                break
            
            # 计算列号
            column = tok.lexpos - self.lexer.lexdata.rfind('\n', 0, tok.lexpos)
            if column < 0:
                column = tok.lexpos + 1
            
            # 创建Token对象
            token = Token(tok.type, tok.value, tok.lineno, column)
            self.token_list.append(token)
        
        return self.token_list
    
    def print_tokens(self):
        """打印Token流"""
        print("Token流:")
        for token in self.token_list:
            print(f"  {token}")
    
    def test(self, text):
        """测试词法分析器"""
        print(f"输入SQL: {text}")
        print("-" * 50)
        
        tokens = self.tokenize(text)
        self.print_tokens()
        
        return tokens

# 测试函数
if __name__ == "__main__":
    lexer = SQLLexerV2()
    
    # 测试用例
    test_cases = [
        "CREATE TABLE student(id INT, name VARCHAR, age INT);",
        "INSERT INTO student(id,name,age) VALUES (1,'Alice',20);",
        "SELECT id,name FROM student WHERE age > 18;",
        "DELETE FROM student WHERE id = 1;"
    ]
    
    for test_case in test_cases:
        print("\n" + "="*60)
        lexer.test(test_case)
